# BSD3.0
# cili@163.com

import socket
import tkinter as tk
from tkinter import messagebox
from tkinter import ttk

import hashlib
from http.server import BaseHTTPRequestHandler
from urllib.parse import  parse_qs
import socketserver
import socket
import threading
#from pathlib import Path

url_mapping = {}
#p = Path('data.bin')
#if p.exists():
#    url_mapping = pickle.load(open('data.bin', 'rb'))


class MyTCPServer:
    def __init__(self,port,request_handler):
        self.server_thread = None
        for tport in range(port,60000):
            try:
                self.server = socketserver.ThreadingTCPServer(('', tport), request_handler)
                self.port = tport
                break
            except socket.error as e:
                pass
        self.server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    def start(self):
        if self.server:
            self.server_thread = threading.Thread(target=self.server.serve_forever)
            self.server_thread.daemon = True
            self.server_thread.start()

    def stop(self):
        if self.server is not None:
            stop_thread = threading.Thread(target=self.stop_server_thread)
            stop_thread.start()

    def stop_server_thread(self):
        if self.server is not None:
            self.server.shutdown()
            self.server.server_close()
            if self.server_thread: self.server_thread.join(2)
            self.server_thread = None
            self.server = None

def generate_short_url(original_url, length=8):
    if (not original_url.startswith('http://')) or (not original_url.startswith('https://')):
        original_url = f'https://{original_url}'
    md5_hash = hashlib.md5(original_url.encode('utf-8')).hexdigest()
    short_url = md5_hash[:length]
    return short_url

html = '''
            <html>
            <head>
                <meta charset="utf-8">
            </head>
            <body>
                <form method="post">
                    <input type="text" name="url" placeholder="输入网址">
                    <input type="submit" value="提交">
                </form>
            </body>
            </html>
        '''

class ShortURLHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.connection.settimeout(10)
        self.send_response(200)
        self.send_header('Content-type', 'text/html; charset=utf-8')
        self.end_headers()

        self.wfile.write(html.encode('utf-8'))

    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        post_data = self.rfile.read(content_length).decode('utf-8')
        post_params = parse_qs(post_data)
        if 'url' not in post_params.keys():
            self.send_response(200)
            self.send_header('Content-type', 'text/html; charset=utf-8')
            self.end_headers()
            self.wfile.write(html.encode('utf-8'))
            return

        original_url = post_params['url'][0].strip()
        if original_url.startswith('su.'):
            turl = url_mapping.get(original_url, '/')
            real_url = turl if turl.startswith('http') else f'https://{turl}'
            self.send_response(302)
            self.send_header('Location', real_url)
            self.end_headers()
        else:
            short_url = 'su.' + generate_short_url(original_url, length=10)
            if short_url not in url_mapping.keys():
                url_mapping[short_url] = original_url
                #pickle.dump(url_mapping, open('data.bin', 'wb'))
            self.send_response(200)
            self.send_header('Content-type', 'text/html; charset=utf-8')  # 指定编码为utf-8
            self.end_headers()
            response = f'短网址是: {short_url}'
            self.wfile.write(response.encode('utf-8'))


class WebServerApp:
    def __init__(self, root):
        self.root = root
        self.port = tk.IntVar(value=8080)
        self.ip = socket.gethostbyname(socket.gethostname())
        self.server = MyTCPServer(self.port.get(), ShortURLHandler)
        self.server.start()
        self.port.set(self.server.port)

        self.root.title("简易短网址服务器")
        self.root.resizable(False, False)
        self.create_widgets()
        self.center_windows()
        self.url_text.focus()
        self.url_text.select_range(0, tk.END)

    def create_widgets(self):
        self.ip_label = ttk.Label(self.root, text="IP地址：", anchor='e')
        self.ip_label.grid(row=0, column=0, sticky="e", padx=5, pady=5)
        self.ip_text = ttk.Label(self.root, width=30, text=self.ip)
        self.ip_text.grid(row=0, column=1, sticky="w", padx=5, pady=5)

        self.port_label = ttk.Label(self.root, text="服务端口：", anchor='e')
        self.port_label.grid(row=1, column=0, sticky="e", padx=5, pady=5)
        self.port_text = ttk.Label(self.root, textvariable=self.port, width=30)
        self.port_text.grid(row=1, column=1, sticky="w", padx=5, pady=5)

        self.status_label = ttk.Label(self.root, text="访问地址：", anchor='e')
        self.status_label.grid(row=2, column=0, sticky="e", padx=5, pady=5)

        self.url_text = ttk.Entry(self.root, width=40)
        self.url_text.insert(tk.END, f"http://{self.ip}:{self.port.get()}")
        self.url_text.state(['readonly'])
        self.url_text.grid(row=2, column=1, sticky="w", padx=5,pady=5)

        tips=ttk.Label(self.root,text='1. 利用访问地址即可访问短网址服务网站。',anchor= 'e')
        tips.grid(row=3, column=0, columnspan=2, sticky="w", padx=5, pady=5)
        tips = ttk.Label(self.root, text='2. 提交一个网址，会得到一个短网址。', anchor='e')
        tips.grid(row=4, column=0, columnspan=2, sticky="w", padx=5, pady=5)
        tips = ttk.Label(self.root, text='3. 提交一个短网址，会自动方位实际对应的网址。', anchor='e')
        tips.grid(row=5, column=0, columnspan=2, sticky="w", padx=5, pady=5)

    def center_windows(self):
        self.root.update()
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        window_width = self.root.winfo_width()
        window_height = self.root.winfo_height()
        x_coordinate = int((screen_width / 2) - (window_width / 2))
        y_coordinate = int((screen_height / 2) - (window_height / 2))
        self.root.geometry("+{}+{}".format(x_coordinate, y_coordinate))

if __name__ == "__main__":
    root = tk.Tk()
    app = WebServerApp(root)
    root.mainloop()
